home *** CD-ROM | disk | FTP | other *** search
-
- /*
- * console.c
- *
- * Copyright (c) 1991 Symantec Corporation. All rights reserved.
- *
- */
-
- #include <MacHeaders>
-
- extern void redraw_graphics(), resize_record(); /* mak */
- extern WindowPtr graphics_window, listener_window; /* mak */
-
- /* remove this line to work on ALL systems */
- #include <PrintTraps.h> /* requires System 4.1 */
-
- #ifndef __PRINTTRAPS__
- #include <Printing.h>
- #endif
-
- #include "stdio.h"
- #include "stddef.h"
- #include "stdlib.h"
- #include "string.h"
- #include "signal.h"
- #include "errno.h"
- #include "console.h"
- #include "ansi_private.h"
-
- struct __copt console_options = { 50, 10, "\pconsole", 8, 4, 9, 0, 25, 80, 1 };
- char __log_stdout;
-
- static void InitConsole(void);
- static void ProcessEvent(void);
- static WindowPeek new_console(void);
- static void kill_console(void);
- static void closeecho(void);
- static WindowPeek cflush(FILE *);
-
- static void console_exit(void);
- static int consoleio(FILE *, int);
- static pascal void myStdText(short, char *, Point, Point);
-
- static void cleos(int);
- static void cleol(void);
- static void output(unsigned char *, short);
- static void overwrite(unsigned char *, long);
- static void blank(int, int);
- static void insert(char, int);
- static void pad(char, long, long);
- static void paste(int, int);
- static int setcursor(int);
- static TEPtr deactivate(void);
- static void strip(void);
- static char *copy(void);
- static void endcopy(void);
- static void newline(void);
- static void resize(void);
- static void use(WindowPeek);
-
- static int open_console_driver(void);
- static int doClose(void);
- static int doControl(void);
- static void doCursor(void);
- static void doClick(EventRecord *);
- static void doZoom(Point, int);
- static void doGrow(Point);
- static void doSelect(EventRecord *);
- static int doCmdKey(int);
- static void doKey(int);
- static void doCut(void);
- static void doCopy(void);
- static void doPaste(void);
-
- static void print_console(void);
- static void print(void);
-
- static struct console {
- WindowPeek wp;
- short height;
- short width;
- short nrows;
- short ncols;
- Point cursor;
- short tabs;
- TEHandle hTE;
- Point limit;
- Handle pasteH;
- long pasteOfs;
- long pasteLen;
- FILE *echo2fp;
- unsigned raw : 1;
- unsigned cbreak : 1;
- unsigned edit : 1;
- unsigned reading : 1;
- unsigned inverse : 1;
- unsigned spool : 1;
- } c;
-
- static char console_environment, noPrint, interrupted, paused;
- static short console_refnum;
- static MenuHandle appleMenu;
- static WindowPeek theConsole;
-
- struct save {
- WindowPeek console;
- GrafPtr port;
- };
- static void setup(WindowPeek, struct save *);
- static void restore(struct save *);
-
- static struct {
- unsigned char *buf;
- unsigned char *ptr;
- size_t cnt;
- int min;
- int max;
- } in;
-
- struct vector {
- short vJMP;
- int (*vCode)();
- };
-
- #define OFS(x) offsetof(struct drvr, x)
-
- static struct drvr {
- short drvrFlags, drvrDelay, drvrEMask, drvrMenu;
- short drvrOpen, drvrPrime, drvrCtl, drvrStatus, drvrClose;
- char drvrName[10];
- short drvrRTS;
- struct vector vCtl, vClose;
- } drvr = {
- 0x0760, 0, 0x016A, 0,
- OFS(drvrRTS), OFS(drvrRTS), OFS(vCtl), OFS(drvrRTS), OFS(vClose),
- "\p.console",
- 0x4E75,
- { 0x4EF9 }, { 0x4EF9 }
- }, **drvrH;
-
- #define hiword(x) (((short *) &(x))[0])
- #define loword(x) (((short *) &(x))[1])
-
-
- /* ---------- public entry points ---------- */
-
-
- /*
- * fopenc - open a stream on a new console
- *
- */
-
- FILE *
- fopenc(void)
- {
- return(freopenc(NULL, __getfile()));
- }
-
-
- /*
- * freopenc - reopen a stream on a new or existing console
- *
- * "fp" is closed, if necessary, then opened as a console. If "fp2"
- * is NULL, a new console is created; otherwise "fp2" must refer to
- * a console, and "fp" is made to refer to the same console.
- *
- */
-
- FILE *
- freopenc(FILE *fp2, FILE *fp)
- {
- if (fp == NULL)
- return(NULL);
- if (WWExist)
- InitConsole();
- fclose(fp);
- fp->refnum = -1;
- fp->window = fp2 ? fp2->window : new_console();
- setvbuf(fp, NULL, _IOLBF, BUFSIZ);
- fp->proc = consoleio;
- __atexit_console(console_exit);
- return(fp);
- }
-
-
- /*
- * cgotoxy - position cursor at <x,y>
- *
- * The position of the upper left corner is <1,1>.
- *
- * This routine does NOT check its arguments. Don't place the
- * cursor off-screen!
- *
- */
-
- void
- cgotoxy(int x, int y, FILE *fp)
- {
- struct save save;
-
- setup(cflush(fp), &save);
- c.cursor.h = x - 1;
- c.cursor.v = y - 1;
- restore(&save);
- }
-
-
- /*
- * cgetxy - report the current cursor position
- *
- * The position of the upper left corner is <1,1>.
- *
- */
-
- void
- cgetxy(int *x, int *y, FILE *fp)
- {
- struct save save;
-
- setup(cflush(fp), &save);
- *x = c.cursor.h + 1;
- *y = c.cursor.v + 1;
- restore(&save);
- }
-
-
- /*
- * ccleos - clear from cursor to end of screen
- *
- * The line containing the cursor, and all following lines, are erased.
- * The cursor is left at the start of the first line erased.
- *
- */
-
- void
- ccleos(FILE *fp)
- {
- struct save save;
-
- setup(cflush(fp), &save);
- cleos(c.cursor.v);
- restore(&save);
- }
-
-
- /*
- * ccleol - clear from cursor to end of line
- *
- */
-
- void
- ccleol(FILE *fp)
- {
- struct save save;
-
- setup(cflush(fp), &save);
- cleol();
- restore(&save);
- }
-
-
- /*
- * csettabs - set tab stops
- *
- */
-
- void
- csettabs(int tabs, FILE *fp)
- {
- struct save save;
-
- setup(cflush(fp), &save);
- if (tabs < 1 || tabs > c.ncols)
- tabs = 1;
- c.tabs = tabs;
- restore(&save);
- }
-
-
- /*
- * csetmode - set console mode
- *
- */
-
- void
- csetmode(int mode, FILE *fp)
- {
- struct save save;
-
- setup(cflush(fp), &save);
- c.raw = c.cbreak = c.edit = 0;
- switch (mode) {
- case C_RAW:
- c.raw = 1;
- break;
- case C_CBREAK:
- c.cbreak = 1;
- break;
- case C_NOECHO:
- break;
- case C_ECHO:
- c.edit = 1;
- break;
- }
- restore(&save);
- }
-
-
- /*
- * cinverse - set inverse video mode
- *
- * As a side effect, the entire screen is erased. The cursor is moved
- * to the start of its line.
- *
- */
-
- void
- cinverse(int on, FILE *fp)
- {
- register WindowPeek wp = cflush(fp);
- struct save save;
-
- setup(wp, &save);
- if (on) {
- if (!wp->port.grafProcs) {
- wp->port.grafProcs = malloc(sizeof(QDProcs));
- SetStdProcs(wp->port.grafProcs);
- wp->port.grafProcs->textProc = (Ptr) myStdText;
- }
- }
- else {
- if (wp->port.grafProcs) {
- free(wp->port.grafProcs);
- wp->port.grafProcs = 0;
- }
- }
- cleos(0);
- restore(&save);
- }
-
-
- /*
- * cshow - show a console window
- *
- * All pending output to the window is forced to appear.
- *
- */
-
- void
- cshow(FILE *fp)
- {
- WindowPeek wp = cflush(fp);
-
- if (wp != (WindowPeek) FrontWindow())
- SelectWindow(wp);
- ShowWindow(wp);
- }
-
-
- /*
- * chide - hide a console window
- *
- */
-
- void
- chide(FILE *fp)
- {
- HideWindow(cflush(fp));
- }
-
-
- /*
- * cecho2file - echo console display to file
- *
- */
-
- void
- cecho2file(char *s, int append, FILE *fp)
- {
- struct save save;
-
- setup(cflush(fp), &save);
- closeecho();
- c.echo2fp = fopen(s, append ? "a" : "w");
- c.spool = 0;
- restore(&save);
- }
-
-
- /*
- * cecho2printer - echo console display to printer
- *
- */
-
- void
- cecho2printer(FILE *fp)
- {
- struct save save;
-
- setup(cflush(fp), &save);
- closeecho();
- c.echo2fp = tmpfile();
- c.spool = 1;
- restore(&save);
- }
-
-
- /* ---------- console management ---------- */
-
-
- /*
- * __open_std - open the std streams
- *
- * This is called automatically (by "__checkfile") whenever an
- * unopened std stream is referenced.
- *
- */
-
- void
- __open_std(void)
- {
- FILE *fp = NULL;
- char buf[40];
-
- if (stdin->std)
- fp = freopenc(fp, stdin);
- if (stdout->std)
- fp = freopenc(fp, stdout);
- if (stderr->std)
- fp = freopenc(fp, stderr);
- if (__log_stdout) {
- sprintf(buf, "%#s.log", CurApName);
- cecho2file(buf, 1, stdout);
- console_options.pause_atexit = 0;
- }
- }
-
-
- /*
- * InitConsole - initialize the console environment
- *
- */
-
- static void
- InitConsole(void)
- {
- MenuHandle menu;
- int i;
-
- /* initialize the Memory Manager */
-
- if (ROM85 >= 0)
- MaxApplZone();
- for (i = 0; i < 10; i++)
- MoreMasters();
-
- /* initialize Quickdraw */
-
- InitGraf(NewPtr(206) + 202);
-
- /* initialize the Toolbox */
-
- InitFonts();
- InitWindows();
- TEInit();
- InitDialogs(0);
- InitMenus();
-
- /* create menus */
-
- InsertMenu(appleMenu = NewMenu(1, "\p\024"), 0);
- AppendMenu(appleMenu, "\pAbout Berkeley Logo;(-");
- AddResMenu(appleMenu, 'DRVR');
- InsertMenu(menu = NewMenu(2, "\pFile"), 0);
- AppendMenu(menu, "\pQuit/Q");
- InsertMenu(menu = NewMenu(3, "\pEdit"), 0);
- AppendMenu(menu, "\pUndo/Z;(-;Cut/X;Copy/C;Paste/V;Clear");
- DrawMenuBar();
-
- /* ready to receive events */
-
- FlushEvents(everyEvent, 0);
- InitCursor();
- console_environment = 1;
- }
-
-
- /*
- * ProcessEvent - handle one event
- *
- */
-
- static void
- ProcessEvent(void)
- {
- int key;
- EventRecord event;
- WindowPeek wp;
- long choice;
- Str255 buf;
- DialogPtr myDialog;
-
- /* process key from paste buffer */
-
- if (c.pasteH) {
- key = (unsigned char) (*c.pasteH)[c.pasteOfs++];
- if (c.pasteOfs == c.pasteLen) {
- DisposHandle(c.pasteH);
- c.pasteH = 0;
- }
- if (c.inverse)
- key &= 0x7F;
- if (key == '\t')
- key = ' ';
- doKey(key);
- return;
- }
-
- /* check for an event */
-
- SystemTask();
- SEvtEnb = false;
- if (GetNextEvent(everyEvent, &event)) {
- if (!SystemEvent(&event))
- goto doEvent;
- }
- else if (event.what == nullEvent) {
- if (FrontWindow() == 0)
- InitCursor();
- }
- return;
-
- /* handle event */
-
- doEvent:
- if (event.what == mouseDown) {
- switch (FindWindow(event.where, &wp)) {
- case inMenuBar:
- InitCursor();
- choice = MenuSelect(event.where);
- goto doMenu;
- case inSysWindow:
- SystemClick(&event, wp);
- break;
- }
- }
- return;
-
- /* handle menu choice */
-
- doMenu:
- switch (hiword(choice)) {
- case 1: /* Apple */
- if (loword(choice) == 1) {
- myDialog = GetNewDialog(100,NULL,(WindowPtr)(-1L));
- ModalDialog(NULL,&choice);
- DisposDialog(myDialog);
- }
- else {
- GetItem(appleMenu, loword(choice), buf);
- OpenDeskAcc(buf);
- }
- break;
- case 2: /* File */
- console_options.pause_atexit = 0;
- exit(0);
- /* no return */
- case 3: /* Edit */
- SystemEdit(loword(choice) - 1);
- break;
- }
- HiliteMenu(0);
- }
-
-
- /*
- * new_console - create a new console window
- *
- */
-
- static WindowPeek
- new_console(void)
- {
- GrafPtr savePort;
- struct console **cH;
- static Rect wbox = { 100, 100, 200, 300 };
- register WindowPeek wp;
- Rect bounds;
- FontInfo fontInfo;
- register WStateData *p;
-
- GetPort(&savePort);
- use(0);
-
- /* create the window */
-
- wp = (WindowPeek) NewWindow(0, &wbox, console_options.title, 0, console_options.procID, (Ptr) -1, 0, 0);
- MoveWindow(wp, console_options.left, console_options.top, 0);
- SetPort(c.wp = wp);
-
- /* set up the font characteristics */
-
- TextFont(console_options.txFont);
- TextSize(console_options.txSize);
- TextFace(console_options.txFace);
- GetFontInfo(&fontInfo);
- c.height = fontInfo.ascent + fontInfo.descent + fontInfo.leading;
- c.width = fontInfo.widMax;
-
- /* set console defaults */
-
- c.tabs = 8;
- c.raw = c.cbreak = c.reading = c.inverse = 0;
- c.edit = 1;
- c.pasteH = 0;
- c.echo2fp = 0;
-
- /* set initial window size */
-
- bounds.top = bounds.left = 0;
- bounds.bottom = (c.nrows = console_options.nrows) * c.height + 8;
- bounds.right = (c.ncols = console_options.ncols) * c.width + 8;
- SizeWindow(wp, bounds.right, bounds.bottom, 0);
-
- /* create TE record */
-
- c.hTE = TENew(&bounds, &bounds);
- (**c.hTE).crOnly = -1;
- c.cursor.v = c.nrows - 1;
- cleos(0);
-
- /* set up grow/zoom parameters */
-
- c.limit = botRight(bounds);
- ++c.limit.v, ++c.limit.h;
- LocalToGlobal(&topLeft(bounds));
- LocalToGlobal(&botRight(bounds));
- p = * (WStateData **) wp->dataHandle;
- p->userState = p->stdState = bounds;
-
- /* associate window with console */
-
- asm {
- lea c,a0
- move.l #sizeof(c),d0
- _PtrToHand
- move.l a0,offsetof(WindowRecord,refCon)(wp)
- }
- if (!console_refnum)
- console_refnum = open_console_driver();
- wp->windowKind = console_refnum;
-
- /* done */
-
- resize();
- ShowWindow(wp);
- SetPort(savePort);
- return(wp);
- }
-
-
- /*
- * kill_console - close a console window
- *
- * The console is not closed if more than one stream shares it.
- *
- */
-
- static void
- kill_console(void)
- {
- register FILE *fp;
- int i = 0, n;
-
- /* see if more than one stream shares this console */
-
- for (fp = &__file[0], n = FOPEN_MAX; n--; fp++) {
- if (fp->window == c.wp && i++)
- return;
- }
-
- /* close echo file (if any) */
-
- closeecho();
-
- /* discard console data structures */
-
- if (c.pasteH)
- DisposHandle(c.pasteH);
- DisposHandle((Handle) c.wp->refCon);
- TEDispose(c.hTE);
- DisposeWindow(c.wp);
- c.wp = 0;
- }
-
-
- /*
- * closeecho - close echo file (if any)
- *
- */
-
- static void
- closeecho(void)
- {
- if (c.echo2fp) {
- if (c.spool)
- print_console();
- fclose(c.echo2fp);
- }
- }
-
-
- /*
- * cflush - flush all pending output to a console
- *
- */
-
- static WindowPeek
- cflush(FILE *fp)
- {
- WindowPeek wp = __checkfile(fp)->window;
- int n;
-
- for (fp = &__file[0], n = FOPEN_MAX; n--; fp++) {
- if (fp->dirty && fp->window == wp)
- fflush(fp);
- }
- return(wp);
- }
-
-
- /* ---------- vectored entry points ---------- */
-
-
- /*
- * console_exit - console shutdown routine
- *
- */
-
- static void
- console_exit(void)
- {
- register FILE *fp;
- int n;
-
- /* complete pending output */
-
- for (fp = &__file[0], n = FOPEN_MAX; n--; fp++) {
- if (fp->dirty && fp->window)
- fflush(fp);
- }
-
- /* pause for user acknowledgement */
-
- if (console_environment && console_options.pause_atexit) {
- for (fp = &__file[0], n = FOPEN_MAX; n--; fp++) {
- if (fp->window) {
- SetWTitle(fp->window, "\ppress «return» to exit");
- c.raw = c.cbreak = c.edit = 0;
- setbuf(fp, NULL);
- fgetc(fp);
- break;
- }
- }
- }
-
- /* close consoles */
-
- for (fp = &__file[0], n = FOPEN_MAX; n--; fp++) {
- if (fp->window)
- fclose(fp);
- }
- }
-
-
- /*
- * consoleio - I/O handler proc for console windows
- *
- */
-
- static int
- consoleio(FILE *fp, int i)
- {
- struct save save;
- int result = 0;
-
- if (_abnormal_exit)
- return(0);
- setup(fp->window, &save);
- switch (i) {
-
- /* read */
-
- case 0:
- in.buf = in.ptr = fp->ptr;
- if (console_environment) {
- cshow(fp);
- c.reading = 1;
- in.cnt = fp->cnt;
- if (c.edit && c.cursor.h + in.cnt > c.ncols)
- in.cnt = c.ncols - c.cursor.h + 1;
- in.min = in.max = c.raw ? 0 : setcursor(0);
- fp->eof = 0;
- do {
- ProcessEvent();
- } while (in.cnt && !c.raw);
- c.reading = 0;
- }
- if ((fp->cnt = in.ptr - in.buf) == 0) {
- fp->eof = 1;
- result = EOF;
- }
- break;
-
- /* write */
-
- case 1:
- output(fp->ptr, fp->cnt);
- break;
-
- /* close */
-
- case 2:
- kill_console();
- if (fp->window == save.console)
- save.console = 0;
- break;
- }
-
- /* check for interrupt */
-
- if (interrupted) {
- interrupted = 0;
- FlushEvents(keyDownMask, 0);
- fp->cnt = 0;
- raise(SIGINT);
- errno = EINTR;
- result = EOF;
- }
-
- if (paused) {
- paused = 0;
- FlushEvents(keyDownMask, 0);
- fp->cnt = 0;
- raise(SIGABRT);
- errno = EINTR;
- result = EOF;
- }
-
- /* done */
-
- restore(&save);
- return(result);
- }
-
-
- /*
- * myStdText - inverse video handler
- *
- */
-
- static pascal void
- myStdText(register short n, register char *s, Point numer, Point denom)
- {
- register char *t;
- char buf;
-
- while (n--) {
- t = s;
- asm {
- @1 tst.b (s)+
- @2 dbmi n,@1
- bpl.s @3
- subq.l #1,s
- @3 }
- if (s > t)
- StdText(s - t, t, numer, denom);
- if (n < 0)
- break;
- buf = *s++ & 0x7F;
- TextMode(notSrcCopy);
- StdText(1, &buf, numer, denom);
- TextMode(srcCopy);
- }
- }
-
-
- /* ---------- I/O primitives ---------- */
-
-
- /*
- * cleos - clear to end of screen
- *
- * The given line, and all following lines, are erased. The cursor is
- * moved to the start of its line.
- *
- */
-
- static void
- cleos(int i)
- {
- pad('\r', 0, c.nrows - i);
- paste((**c.hTE).lineStarts[i], (**c.hTE).teLength);
- c.cursor.h = 0;
- }
-
-
- /*
- * cleol - clear to end of line
- *
- */
-
- static void
- cleol(void)
- {
- register TEPtr pTE = deactivate();
- register short *line = &pTE->lineStarts[c.cursor.v];
- register int selStart = line[0] + c.cursor.h;
- register int selEnd = line[1] - 1;
-
- if (selStart < selEnd) {
- pTE->selStart = selStart;
- pTE->selEnd = selEnd;
- TEDelete(c.hTE);
- }
- }
-
-
- /*
- * output - write characters to the current console
- *
- */
-
- static void
- output(register unsigned char *s, register short n)
- {
- unsigned char *t;
- register EvQElPtr q;
-
- while (n--) {
- t = s;
- asm {
- moveq #' ',d0
- @1 cmp.b (s)+,d0
- @2 dbhi n,@1
- bls.s @3
- subq.l #1,s
- @3 }
- if (s > t)
- overwrite(t, s - t);
- if (n < 0)
- break;
- if (!c.raw) {
- for (q = (EvQElPtr) EventQueue.qHead; q; q = (EvQElPtr) q->qLink) {
- if (q->evtQWhat == keyDown && (char) q->evtQMessage == '.') {
- if (q->evtQModifiers & cmdKey) {
- interrupted = 1;
- return;
- }
- }
- }
- for (q = (EvQElPtr) EventQueue.qHead; q; q = (EvQElPtr) q->qLink) {
- if (q->evtQWhat == keyDown && (char) q->evtQMessage == ',') {
- if (q->evtQModifiers & cmdKey) {
- paused = 1;
- return;
- }
- }
- }
- }
- switch (*s++) {
- case '\a':
- SysBeep(4);
- break;
- case '\b':
- deactivate();
- if (c.cursor.h)
- --c.cursor.h;
- break;
- case '\f':
- c.cursor.v = 0;
- cleos(0);
- break;
- case '\n':
- newline();
- break;
- case '\v':
- if (++c.cursor.v == c.nrows)
- --c.cursor.v;
- break;
- case '\r':
- c.cursor.h = 0;
- break;
- case '\t':
- do {
- ++c.cursor.h;
- } while (c.cursor.h % c.tabs);
- if (c.cursor.h > c.ncols)
- c.cursor.h = c.ncols;
- break;
- }
- }
- }
-
-
- /*
- * overwrite - place new text on a line
- *
- * The text must not contain any control characters. Text is drawn
- * starting at the current cursor, overwriting any existing characters.
- * The cursor is left at the end of the new text.
- *
- */
-
- static void
- overwrite(unsigned char *s, long n)
- {
- register long m;
- register short *line, selStart, selEnd;
-
- /* wrap output at "ncols" */
-
- more:
- if (c.cursor.h + (m = n) > c.ncols)
- m = c.ncols - c.cursor.h;
-
- /* set replacement range */
-
- line = &(**c.hTE).lineStarts[c.cursor.v];
- selStart = line[0] + c.cursor.h;
- selEnd = line[1] - 1;
- if (selStart > selEnd) { /* pad line with blanks */
- pad(' ', 0, selStart - selEnd);
- paste(selEnd, selEnd);
- selEnd = selStart;
- }
- else if (selEnd > selStart + m)
- selEnd = selStart + m;
-
- /* paste in new text */
-
- PtrToXHand(s, TEScrpHandle, m);
- TEScrpLength = m;
- paste(selStart, selEnd);
-
- /* wrap to next line if necessary */
-
- if (m < n) {
- newline();
- s += m;
- n -= m;
- goto more;
- }
- c.cursor.h += m;
- }
-
-
- /*
- * blank - erase the indicated portion of the input field
- *
- */
-
- static void
- blank(int selStart, int selEnd)
- {
- register TEPtr pTE = deactivate();
-
- if (in.max + 1 == pTE->lineStarts[c.cursor.v + 1]) {
- pTE->selStart = selStart;
- pTE->selEnd = selEnd;
- TEDelete(c.hTE);
- }
- else {
- pTE->selStart = selEnd;
- pTE->selEnd = in.max;
- TECopy(c.hTE);
- pad(' ', in.max - selEnd, in.max - selStart);
- paste(selStart, in.max);
- }
- in.max -= selEnd - selStart;
- }
-
-
- /*
- * insert - insert a character at the indicated point
- *
- */
-
- static void
- insert(char ch, int selStart)
- {
- register TEPtr pTE = deactivate();
-
- pTE->selStart = selStart;
- if (in.max + 1 == pTE->lineStarts[c.cursor.v + 1]) {
- pTE->selEnd = selStart;
- TEKey(ch, c.hTE);
- }
- else {
- pTE->selEnd = in.max;
- TECopy(c.hTE);
- Munger(TEScrpHandle, 0, 0, 0, &ch, 1);
- ++TEScrpLength;
- paste(selStart, in.max + 1);
- }
- in.max++;
- }
-
-
- /*
- * pad - pad the TE scrap to a desired size
- *
- */
-
- static void
- pad(register char ch, register long ofs, register long len)
- {
- /* set scrap size */
-
- asm {
- movea.l TEScrpHandle,a0
- move.l len,d0
- move.w d0,TEScrpLength
- _SetHandleSize
- }
-
- /* fill scrap */
-
- asm {
- movea.l (a0),a0
- adda.l ofs,a0
- sub.l ofs,len
- bra.s @2
- @1 move.b ch,(a0)+
- @2 dbra len,@1
- }
- }
-
-
- /*
- * paste - replace range with contents of TEScrap
- *
- */
-
- static void
- paste(int selStart, int selEnd)
- {
- register TEPtr pTE = deactivate();
-
- pTE->selStart = selStart;
- pTE->selEnd = selEnd;
- TEPaste(c.hTE);
- }
-
-
- /*
- * setcursor - activate flashing caret at cursor
- *
- */
-
- static int
- setcursor(int sel)
- {
- register TEPtr pTE = deactivate();
- register short *line = &pTE->lineStarts[c.cursor.v];
- register int end = line[1] - 1;
-
- sel += line[0] + c.cursor.h;
- if (sel > end) { /* pad line with blanks */
- pad(' ', 0, sel - end);
- paste(end, end);
- pTE = *c.hTE;
- }
- pTE->selStart = pTE->selEnd = sel;
- pTE->clikStuff = 255; /* per TN127 */
- TEActivate(c.hTE);
- return(sel);
- }
-
-
- /*
- * deactivate - make sure TE record is inactive
- *
- * The dereferenced pointer to the TE record is returned.
- *
- */
-
- static TEPtr
- deactivate(void)
- {
- if ((**c.hTE).active)
- TEDeactivate(c.hTE);
- return(*c.hTE);
- }
-
-
- /*
- * strip - strip trailing blanks from all lines
- *
- * Note that we don't strip blanks that are part of the current
- * input field.
- *
- */
-
- static void
- strip(void)
- {
- register int i = c.nrows, j, k;
- register TEPtr pTE = *c.hTE;
- register char *p;
-
- while (i) {
- j = k = pTE->lineStarts[i--] - 1;
- for (p = *pTE->hText + j; j && *--p == ' '; j--)
- ;
- if (c.reading && !c.raw && i == c.cursor.v && j < in.max)
- j = in.max;
- if (k -= j) {
- Munger(pTE->hText, j, 0, k, "", 0);
- pTE = *c.hTE;
- if (c.reading) {
- if (in.min > j)
- in.min -= k;
- if (in.max > j)
- in.max -= k;
- }
- if (pTE->selStart > j)
- pTE->selStart -= k;
- if (pTE->selEnd > j)
- pTE->selEnd -= k;
- }
- }
- TECalText(c.hTE);
- }
-
-
- /*
- * resize - respond to new window size
- *
- * If the window is too small to display the entire console, the lower
- * left portion of the console is displayed.
- *
- */
-
- static void
- resize(void)
- {
- Rect bounds;
-
- bounds = c.wp->port.portRect;
- InvalRect(&bounds);
- InsetRect(&bounds, 4, 4);
- (**c.hTE).viewRect = bounds;
- bounds.top = bounds.bottom - c.height * c.nrows;
- (**c.hTE).destRect = bounds;
- }
-
-
- /*
- * setup - focus on the appropriate console
- *
- * The current console and the current grafport are set appropriately,
- * and the previous values are saved. Any pending update is performed.
- *
- */
-
- static void
- setup(WindowPeek wp, struct save *save)
- {
- Rect bounds;
-
- GetPort(&save->port);
- save->console = theConsole;
- if (wp && wp->windowKind == console_refnum) {
- use(wp);
- SetPort(wp);
- if (!EmptyRgn(wp->updateRgn)) {
- bounds = wp->port.portRect;
- BeginUpdate(wp);
- EraseRect(&bounds);
- TEUpdate(&bounds, c.hTE);
- if (wp == graphics_window) /* mak */
- redraw_graphics();
- EndUpdate(wp);
- }
- theConsole = wp;
- }
- }
-
-
- /*
- * restore - done with the current console
- *
- * The console and grafport saved by a previous "setup" call are restored.
- *
- */
-
- static void
- restore(struct save *save)
- {
- if (theConsole = save->console)
- use(save->console);
- SetPort(save->port);
- }
-
-
- /*
- * use - load global "c" from window's refCon
- *
- */
-
- static void
- use(WindowPeek wp)
- {
- if (wp != c.wp) {
- if (c.wp)
- ** (struct console **) c.wp->refCon = c;
- if (wp)
- c = ** (struct console **) wp->refCon;
- }
- }
-
-
- /*
- * copy - get a pointer to the text in the TE scrap
- *
- * If inverse video is in use, the high bit is stripped from each byte.
- * This call must be balanced by a call to "endcopy".
- *
- */
-
- static char *
- copy(void)
- {
- asm {
- movea.l TEScrpHandle,a0
- _HLock
- move.l (a0),d0
- }
- if (c.inverse) asm {
- movea.l d0,a1
- move.w TEScrpLength,d1
- bra.s @2
- @1 tst.b (a1)+
- bpl.s @2
- bclr #7,-1(a1)
- @2 dbra d1,@1
- }
- }
-
-
- /*
- * endcopy - done using text obtained by "copy"
- *
- */
-
- static void
- endcopy(void)
- {
- HUnlock(TEScrpHandle);
- }
-
-
- /*
- * newline - print a newline character
- *
- */
-
- static void
- newline(void)
- {
- register TEPtr pTE = deactivate();
- register short *line, delta, len;
- Rect bounds;
- RgnHandle rgn;
- Handle hText;
- EventRecord event;
-
- if (c.reading && !c.edit && !c.cbreak)
- return;
-
- /* wait while mouse is down */
-
- if (GetOSEvent(mDownMask, &event)) {
- while (!GetOSEvent(mUpMask, &event))
- ;
- }
-
- /* copy current line to echo-file */
-
- if (c.echo2fp) {
- line = &pTE->lineStarts[c.cursor.v];
- pTE->selStart = line[0];
- pTE->selEnd = line[1];
- TECopy(c.hTE);
- fwrite(copy(), 1, TEScrpLength, c.echo2fp);
- endcopy();
- }
-
- /* advance cursor, scrolling if necessary */
-
- if (++c.cursor.v == c.nrows) {
- pTE = *c.hTE;
- hText = pTE->hText;
- len = pTE->teLength -= delta = pTE->lineStarts[1];
- ++pTE->teLength;
- bounds = pTE->destRect;
- ScrollRect(&bounds, 0, -c.height, rgn = NewRgn());
- DisposeRgn(rgn);
- Munger(hText, 0, 0, delta, "", 0);
- Munger(hText, len, 0, 0, "\r", 1);
- TECalText(c.hTE);
- --c.cursor.v;
- }
- c.cursor.h = 0;
- }
-
-
- /* ---------- console driver ---------- */
-
-
- /*
- * open_console_driver - install and initialize the console driver
- *
- */
-
- static int
- open_console_driver(void)
- {
- short i;
- DCtlHandle dceH;
- register DCtlPtr dce;
-
- /* create driver on heap */
-
- if (!drvrH) {
- drvr.vCtl.vCode = doControl;
- drvr.vClose.vCode = doClose;
- asm {
- lea drvr,a0
- move.l #sizeof(drvr),d0
- _PtrToHand
- move.l a0,drvrH
- }
- }
-
- /* find available slot in unit table */
-
- for (i = 27; dceH = UTableBase[i]; i++) {
- if (!((**dceH).dCtlFlags & dOpened))
- break;
- }
- i = ~i;
-
- /* create DCE */
-
- asm {
- move.w i,d0
- dc.w 0xA13D ; _DrvrInstall
- movea.l (a0),dce
- }
- dce->dCtlDriver = (Ptr) drvrH;
- dce->dCtlFlags = drvr.drvrFlags;
- dce->dCtlEMask = drvr.drvrEMask;
- return(i);
- }
-
-
- /*
- * doClose - handle _PBClose call
- *
- * Normally, we shouldn't get a close call, because a console window has
- * no go-away box. If we do reach here, we can keep from crashing (except
- * on 64K ROMs) by refusing to close.
- *
- */
-
- static int
- doClose(void)
- {
- return(closErr);
- }
-
-
- /*
- * doControl - handle _PBControl call
- *
- */
-
- static int
- doControl(void)
- {
- register CntrlParam *pb;
- DCtlPtr dce;
- struct save save, save2;
- register EventRecord *event;
- int key;
- long oldA5 = SetCurrentA5();
-
- asm {
- move.l a0,pb
- move.l a1,dce
- }
- setup((WindowPeek) FrontWindow(), &save);
- switch (pb->csCode) {
- case accCursor:
- doCursor();
- break;
- case accCut:
- doCut();
- break;
- case accCopy:
- doCopy();
- break;
- case accPaste:
- doPaste();
- break;
- case accClear:
- doKey('\33');
- break;
- case accEvent:
- event = * (EventRecord **) pb->csParam;
- switch (event->what) {
- case updateEvt:
- setup((WindowPeek) event->message, &save2);
- break;
- case mouseDown:
- doClick(event);
- break;
- case keyDown:
- case autoKey:
- key = (unsigned char) event->message;
- if (event->modifiers & cmdKey) {
- if (event->what == autoKey)
- break;
- key = doCmdKey(key);
- }
- if (key)
- doKey(key);
- break;
- }
- break;
- }
- HUnlock(drvrH);
- HUnlock(RecoverHandleSys(dce));
- restore(&save);
- SetA5(oldA5);
- return(0);
- }
-
-
- /*
- * doCursor - cursor maintenance
- *
- */
-
- static void
- doCursor(void)
- {
- Point where;
-
- TEIdle(c.hTE);
- GetMouse(&where);
- if (PtInRect(where, &c.wp->port.portRect))
- SetCursor(*GetCursor(iBeamCursor));
- else asm {
- movea.l (a5),a0
- pea -108(a0) ; arrow
- _SetCursor
- }
- }
-
-
- /*
- * doClick - handle mouse-down event
- *
- * Since the click was passed to the console driver, the front window
- * must be a console window, and the click can only be in its zoom box
- * or content region (including the grow region).
- *
- */
-
- static void
- doClick(EventRecord *event)
- {
- int part;
-
- c.wp->windowKind = userKind;
- part = FindWindow(event->where, &c.wp);
- c.wp->windowKind = console_refnum;
- switch (part) {
- case inZoomIn:
- case inZoomOut:
- doZoom(event->where, part);
- break;
- case inGrow:
- if (!(event->modifiers & (cmdKey|optionKey))) {
- doGrow(event->where);
- break;
- }
- /* ... */
- case inContent:
- doSelect(event);
- break;
- }
- }
-
-
- /*
- * doZoom - handle click in zoom box
- *
- * The "zoomed" size is that needed to display the entire console.
- *
- */
-
- static void
- doZoom(Point where, int part)
- {
- register WindowPeek wp = c.wp;
-
- InitCursor();
- if (TrackBox(wp, where, part)) {
- EraseRect(&wp->port.portRect);
- ZoomWindow(wp, part, 0);
- resize();
- }
- }
-
-
- /*
- * doGrow - handle click in grow region
- *
- * No grow box is actually visible; nonetheless, clicking in the lower
- * right corner has the same effect. Hold down the command or option
- * key to defeat this behavior (e.g. to select corner text).
- *
- * The maximum window size is that needed to display the entire console.
- *
- */
-
- static void
- doGrow(Point where)
- {
- register WindowPeek wp = c.wp;
- long size;
- static Rect limit = { 76, 120, 9999, 9999 }; /* mak */
- int old_right, old_bottom; /* mak */
-
- InitCursor();
- botRight(limit) = c.limit;
- if (size = GrowWindow(wp, where, &limit)) {
- EraseRect(&wp->port.portRect);
- if (wp == graphics_window) {
- old_right = graphics_window->portRect.right;
- old_bottom = graphics_window->portRect.bottom;
- }
-
- SizeWindow(wp, (loword(size) | 1) - 1, (hiword(size) | 1) - 1, 0); /* mak */
- resize();
- if (wp == graphics_window) /* mak */
- resize_record((graphics_window->portRect.right - old_right) / 2,
- (graphics_window->portRect.bottom - old_bottom) / 2);
- }
- }
-
-
- /*
- * doSelect - handle click in content region, initiating selection
- *
- */
-
- static void
- doSelect(EventRecord *event)
- {
- int extend = 0;
- register TEPtr pTE;
-
- if (!(**c.hTE).active)
- setcursor(0);
- else if (event->modifiers & shiftKey)
- extend = 1;
- strip();
-
- /* let TE do the work */
-
- GlobalToLocal(&event->where);
- TEClick(event->where, extend, c.hTE);
- pTE = *c.hTE;
-
- /* fix selection */
-
- if (pTE->selStart == pTE->selEnd) {
- pTE->clikStuff = 255; /* per TN127 */
- if (!c.reading || c.raw)
- TEDeactivate(c.hTE);
- else if (pTE->selStart < in.min)
- TESetSelect(in.min, in.min, c.hTE);
- else if (pTE->selEnd > in.max)
- TESetSelect(in.max, in.max, c.hTE);
- }
- }
-
-
- /*
- * doCmdKey - handle command key
- *
- */
-
- static int
- doCmdKey(int key)
- {
- if (c.raw)
- return(key & 0x1F); /* controlify */
- switch (key) {
- case 'x': case 'X':
- doCut();
- break;
- case 'c': case 'C':
- doCopy();
- break;
- case 'v': case 'V':
- doPaste();
- break;
- case '.':
- if (console_environment)
- interrupted = 1;
- case ',':
- if (console_environment)
- paused = 1;
- /* ... */
- case 'd': case 'D':
- return('\4'); /* ctrl-D */
- case 'u': case 'U':
- case 'z': case 'Z':
- return('\25'); /* ctrl-U */
- case 'q': case 'Q':
- if (console_environment) {
- console_options.pause_atexit = 0;
- exit(0);
- }
- break;
- }
- return(0);
- }
-
-
- /*
- * doKey - handle keypress
- *
- */
-
- static void
- doKey(int key)
- {
- register TEPtr pTE = *c.hTE;
- register int selStart = pTE->selStart;
- register int selEnd = pTE->selEnd;
- register short len;
- register char *p;
-
- if (!c.reading || c.inverse && key > 0x7F)
- goto beep;
- if (c.raw) {
- *in.ptr++ = key;
- in.cnt = 0;
- return;
- }
-
- /* process control characters */
-
- if (key < ' ') {
- switch (key) {
- case '\25': /* ^U */
- case '\33': /* escape, clear */
- in.cnt += in.ptr - in.buf;
- in.ptr = in.buf;
- selStart = in.min;
- selEnd = in.max;
- goto blank;
- case '\b': /* backspace */
- if (c.edit)
- goto blank;
- if (c.cbreak)
- goto buffer;
- if (in.ptr == in.buf)
- goto beep;
- --in.ptr;
- ++in.cnt;
- goto cursor;
- case '\34': /* left arrow */
- if (selStart == selEnd)
- --selStart;
- goto cursor;
- case '\35': /* right arrow */
- if (selStart == selEnd)
- ++selEnd;
- selStart = selEnd;
- goto cursor;
- case '\36': /* up arrow */
- selStart = in.min;
- goto cursor;
- case '\37': /* down arrow */
- case '\t': /* tab */
- selStart = in.max;
- goto cursor;
- case '\4': /* ^D */
- case '\r': /* return */
- case '\3': /* enter */
- if (len = in.max - in.min) {
- p = *pTE->hText + in.min;
- asm {
- movea.l in.ptr,a0
- bra.s @2
- @1 move.b (p)+,(a0)+
- @2 dbra len,@1
- move.l a0,in.ptr
- }
- }
- if (key != '\4')
- *in.ptr++ = '\n';
- newline();
- in.cnt = 0;
- break;
- }
- return;
- }
-
- /* delete any existing selection */
-
- blank:
- if (c.edit) {
- if (selStart == selEnd) {
- if (key != '\b')
- goto insert;
- --selStart;
- }
- if (selStart < in.min || selEnd > in.max)
- goto beep;
- blank(selStart, selEnd);
- }
-
- /* insert the key */
-
- insert:
- if (key >= ' ') {
- if (in.max - in.min == in.cnt - 1)
- SysBeep(2);
- else if (c.edit)
- insert(key, selStart++);
- else {
- buffer: *in.ptr++ = key;
- if (c.cbreak) {
- output(in.ptr - 1, 1);
- in.cnt = 0;
- return;
- }
- --in.cnt;
- }
- }
-
- /* update the cursor */
-
- cursor:
- if (selStart > in.max)
- selStart = in.max;
- else if (selStart < in.min)
- selStart = in.min;
- setcursor(selStart - in.min);
- return;
-
- /* beep only */
-
- beep:
- SysBeep(2);
- }
-
-
- /*
- * doCut - handle "cut" command
- *
- * Selected text (if any) is placed in the desk scrap, then deleted.
- *
- */
-
- static void
- doCut(void)
- {
- register TEPtr pTE = *c.hTE;
-
- if (pTE->active && pTE->selStart < pTE->selEnd) {
- if (!c.reading || pTE->selStart < in.min || pTE->selEnd > in.max)
- SysBeep(2);
- else {
- doCopy();
- doKey('\b');
- }
- }
- }
-
-
- /*
- * doCopy - handle "copy" command
- *
- * Selected text (if any) is placed in the desk scrap.
- *
- */
-
- static void
- doCopy(void)
- {
- register TEPtr pTE = *c.hTE;
-
- if (pTE->active && pTE->selStart < pTE->selEnd) {
- TECopy(c.hTE);
- ZeroScrap();
- PutScrap(TEScrpLength, 'TEXT', copy());
- endcopy();
- }
- }
-
-
- /*
- * doPaste - handle "paste" command
- *
- * Pasted text is obtained from the desk scrap and stored in the paste
- * buffer, "c.pasteH". ProcessEvent will take characters from the buffer
- * in preference to the keyboard.
- *
- */
-
- static void
- doPaste(void)
- {
- if (!c.reading || (**c.hTE).selStart < in.min || (**c.hTE).selEnd > in.max) {
- SysBeep(2);
- return;
- }
- if ((c.pasteLen = GetScrap(TEScrpHandle, 'TEXT', &c.pasteOfs)) > 0) {
- c.pasteH = TEScrpHandle;
- TEScrpHandle = NewHandle(0);
- c.pasteOfs = 0;
- }
- TEScrpLength = 0;
- }
-
-
- /* ---------- printing ---------- */
-
-
- /*
- * print_console - print the echo file
- *
- */
-
- static void
- print_console(void)
- {
- /* check for availability of printing */
-
- #ifdef __PRINTTRAPS__
- if (GetTrapAddress(0xA8FD) == GetTrapAddress(0xA89F)) {
- c.echo2fp->remove = 0;
- return;
- }
- #endif
-
- /* print away */
-
- if (!noPrint) {
- PrOpen();
- if (!PrError()) {
- print();
- PrClose();
- }
- }
- }
-
-
- /*
- * print - spool file to printer
- *
- */
-
- static void
- print(void)
- {
- static THPrint hPrint;
- THPrint h;
- GrafPtr savePort;
- TPPrPort port;
- register TEPtr pTE;
- int ascent, nlines, i;
- Rect pageRect;
- Point where;
- char buf[BUFSIZ];
- TPrStatus status;
-
- /* set up job record */
-
- h = (THPrint) NewHandle(sizeof(TPrint));
- PrintDefault(h);
- if (hPrint) {
- PrJobMerge(hPrint, h);
- DisposHandle(hPrint);
- }
- else {
- InitCursor();
- if (!PrJobDialog(h)) {
- noPrint = 1;
- return;
- }
- }
- hPrint = h;
-
- /* set up printing port */
-
- GetPort(&savePort);
- port = PrOpenDoc(h, NULL, NULL);
- pTE = *c.hTE;
- TextFont(pTE->txFont);
- TextSize(pTE->txSize);
- TextFace(pTE->txFace);
- ascent = pTE->fontAscent;
- pageRect = (**h).prInfo.rPage;
- nlines = (pageRect.bottom - pageRect.top) / c.height;
- where.h = pageRect.left + 36; /* leave 1/2 inch margin */
-
- /* print each page */
-
- rewind(c.echo2fp);
- c.echo2fp->binary = 0;
- do {
- PrOpenPage(port, NULL);
- where.v = pageRect.top + ascent;
- for (i = 0; i < nlines && fgets(buf, sizeof buf, c.echo2fp); i++) {
- MoveTo(where.h, where.v);
- DrawText(buf, 0, strlen(buf) - 1);
- where.v += c.height;
- }
- PrClosePage(port);
- } while (!PrError() && !feof(c.echo2fp));
-
- /* done printing */
-
- PrCloseDoc(port);
- SetPort(savePort);
- if ((**h).prJob.bJDocLoop == bSpoolLoop && !PrError())
- PrPicFile(h, NULL, NULL, NULL, &status);
- }
-